package cn.assumejson.pro_netty.netty.client.asyn;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author by gang.Li 2022/3/12 10:49
 */
public class RequestFuture {
    // 请求缓存类，key为每次请求id ，value为请求对象
    public static Map<Long, RequestFuture> futures = new ConcurrentHashMap<>();

    private static final AtomicLong aid = new AtomicLong(0);

    private static final ReentrantLock lock = new ReentrantLock();
    private static final Condition condition = lock.newCondition();

    private String path;

    public RequestFuture() {
        id = aid.incrementAndGet();
        addFuture(this);
    }

    /**
     * 请求id
     */
    private long id;
    /**
     * 请求参数
     */
    private Object request;

    /**
     * 响应结果
     */
    private Object result;

    /**
     * 默认的超时时间为5s
     */
    private long timeout = 5000;

    /**
     * 将请求放入到缓存中
     *
     * @param future 请求
     */
    public static void addFuture(RequestFuture future) {
        futures.put(future.getId(), future);
    }

    /**
     * 同步获取响应的结果
     *
     * @return response
     */
    public Object get() {
        synchronized (this) {
            while (this.result == null) {// 死循环了，由于result 没有值
                try {
                    this.wait(timeout);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return this.result;
    }

    public Object getByReentrLock() {
        try {
            lock.tryLock();
            while (this.result == null) {
                try {
                    condition.awaitNanos(timeout);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return this.result;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 异步线程将结果返回主线程
     *
     * @param resp Response
     */
    public static void received(Response resp) {
        RequestFuture future = futures.remove(resp.getId());
        // 设置响应结果

        if (future != null) {
            future.setResult(resp.getResult());
//            condition.signalAll();
            // 通知主线程
            synchronized (future) {
                future.notify();
            }
        }
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    public static Map<Long, RequestFuture> getFutures() {
        return futures;
    }

    public static void setFutures(Map<Long, RequestFuture> futures) {
        RequestFuture.futures = futures;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public Object getRequest() {
        return request;
    }

    public void setRequest(Object request) {
        this.request = request;
    }

    public long getTimeout() {
        return timeout;
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }
}
